﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

/// <summary>
/// This is a simple TCP and UDP based client.
/// </summary>
namespace SocketClient {
	class loader {
		static int dataBufferSize = 4096;
		public static void FormatBuffer(byte[] dataBuffer, string message) {
			byte[] byteMessage = System.Text.Encoding.ASCII.GetBytes(message);
			int runLen = Math.Min(dataBufferSize, message.Length);
			int i = 0;
			while (i < runLen) {
				dataBuffer[i] = byteMessage[i];
				i++;
			}
			if (i >= dataBufferSize) {
				dataBuffer[dataBufferSize - 1] = (byte)'\0';
				return;
			}
			dataBuffer[i] = (byte)'\0';
		}

		static String bufToString(byte[] buffer) {
			string bufOutput = "";
			int i = 0;
			while (buffer[i] != '\0' && i < dataBufferSize) {
				bufOutput += (char)buffer[i];
				i++;
			}
			return bufOutput;
		}

		/// <summary>
		/// This is the main function for the simple client. It parses the command line and creates
		/// a socket of the requested type. For TCP, it will resolve the name and attempt to connect
		/// to each resolved address until a successful connection is made. Once connected a request
		/// message is sent followed by shutting down the send connection. The client then receives
		/// data until the server closes its side at which point the client socket is closed. For
		/// UDP, the socket is created and if indicated connected to the server's address. A single
		/// request datagram message. The client then waits to receive a response and continues to
		/// do so until a zero byte datagram is receive which indicates the end of the response.
		/// </summary>
		/// <param name="args">Command line arguments</param>
		static void Main() {
			SocketType sockType = SocketType.Stream;
			ProtocolType sockProtocol = ProtocolType.Tcp;
			string remoteName = "localhost",
				textMessage = "I'm a stupid client with an ugly face and big butt and my butt smells and I like to kiss my own butt\0";
			bool udpConnect = false;
			int remotePort = 5150, bufferSize = 4096;

			Socket clientSocket = null;
			IPHostEntry resolvedHost = null;
			IPEndPoint destination = null;
			byte[] sendBuffer = new byte[bufferSize], recvBuffer = new Byte[bufferSize];
			int rc;

			// Format the string message into the send buffer
			FormatBuffer(sendBuffer, textMessage);

			try {
				// Try to resolve the remote host name or address
				resolvedHost = Dns.GetHostEntry(remoteName);
				Console.WriteLine("Client: GetHostEntry() is OK...");

				// Try each address returned, will BREAK when a valid one is found
				foreach (IPAddress addr in resolvedHost.AddressList) {
					// Create a socket corresponding to the address family of the resolved address
					clientSocket = new Socket(
						addr.AddressFamily,
						sockType,
						sockProtocol
						);
					//Console.WriteLine("Client: Socket() is OK...");
					try {
						// Create the endpoint that describes the destination
						destination = new IPEndPoint(addr, remotePort);
						//Console.WriteLine("Client: IPEndPoint() is OK. IP Address: {0}, server port: {1}", addr, remotePort);

						if ((sockProtocol == ProtocolType.Udp) && (udpConnect == false)) {
							//Console.WriteLine("Client: Destination address is: {0}", destination.ToString());
							break;
						} else {
							//Console.WriteLine("Client: Attempting connection to: {0}", destination.ToString());
						}
						clientSocket.Connect(destination);
						//Console.WriteLine("Client: Connect() is OK...");
						break;
					} catch (SocketException) {
						// Connect failed, so close the socket and try the next address
						clientSocket.Close();
						//Console.WriteLine("Client: Close() is OK...");
						clientSocket = null;
						continue;
					}
				}
				//end foreach

				if (clientSocket == null) {
					//Console.WriteLine("No open ports found!");
					return;
				}


				// Make sure we have a valid socket before trying to use it
				try	{
						//rc = clientSocket.Send(sendBuffer);
						//Console.WriteLine("Client: send() is OK...TCP...");
						//Console.WriteLine("Client: Sent request of {0} bytes", rc);

						// Receive data in a loop until the server closes the connection. For
						//    TCP this occurs when the server performs a shutdown or closes
						//    the socket. For UDP, we'll know to exit when the remote host
						//    sends a zero byte datagram.
						while (true) {
							rc = clientSocket.Receive(recvBuffer);

							//Console.WriteLine("Client: Receive() is OK...");
							//Console.WriteLine("Client: Read {0} bytes", rc);
							Console.WriteLine("Received: " + bufToString(recvBuffer));
							rc = clientSocket.Send(sendBuffer);

							// Exit loop if server indicates shutdown
							/*
							if (rc == 0) {
								clientSocket.Close();
								Console.WriteLine("Client: Close() is OK...");
								break;
							}
							*/
							Thread.Sleep(1000);
						}
					} catch (SocketException err) {
						//Console.WriteLine("Client: Error occurred while sending or receiving data.");
						//Console.WriteLine("   Error: {0}", err.Message);
					}
			} catch (SocketException err) {
				//Console.WriteLine("Client: Socket error occurred: {0}", err.Message);
			}
		}
	}
}